猛火Fierflame

PWA: 渐进式 Web 应用

说明

虽然我将这篇文章归到 HTML5 API 这一分类中,但确切的说 PWA 并不是单一API,而是对多种API的综合应用。特别的,一个完整的 PWA 需要两个特别的文件——服务线程(一般为 service-worker.js )和Web应用清单(一般为 manifest.jsonmanifest.webmanifest ),本文将主要对这两个文件展开介绍。

服务线程(service worker)

服务线程(service worker),是独立与页面的 WebWorker,其在启动后,会一直在后台运营(直到浏览器被关闭,或在一段时间内,没有该应用打开的的页面),并且可以拦截 Web 请求,将本地缓存甚至是即时生成的数据作为相应返回给原页面。

服务线程上下文环境

因为所有页面的请求可能都要经过服务线程,如果服务线程一但被堵塞,将会导致所有页面的请求都被堵塞,所以服务线程中的所有API均为异步API。

服务线程上下文环境是ServiceWorkerGlobalScope的实例,除了ECMAScript定义的语法级对象外,主要还有以下几个属性:

另外有与windows中同名同用法(或功能相似)的对象,均继承自WorkerGlobalScope,具体见下表:

对象 - - -
btoa location indexedDB addEventListener
atob setTimeout navigator removeEventListener
crypto setInterval performance dispatchEvent
fonts clearTimeout importScripts createImageBitmap
origin clearInterval queueMicrotask

但因为上下文环境的不通,部分API不支持或缺少部分属性成员,如navigator没有keyboardclipboardcookieEnabled等成员。

事件

ServiceWorkerGlobalScope 主要有以下几个事件:

caches

ServiceWorkerGlobalScope.cachesCacheStorage 的实例,主要有以下几个方法:

Cache 实例

通过 ServiceWorkerGlobalScope.caches.open 得到一个 Cache实例,所有的缓存操作均在此对象上实现。其实例主要有以下几个方法:

install 事件与 activate 事件

由于事件是通过继承EventTarget类实现的,所以,使用传统的方式,均会忽略事件回调函数返回的Promise对象,但在服务线程的安装、激活过程中,可能需要一些异步的操作,例如提前缓存部分页面。为确保触发installactivate 事件后,能够保证相关操作完成后再结束这两种状态,install 事件与 activate 事件提供了 waitUntil 方法。

waitUntil 方法接收一个 Promise 对象作为参数,当该 Promise 对象状态转为 fulfilledrejected后,installactivate状态才会结束,单如果不调用waitUntil 方法则直接结束。

fetch 事件

fetch 事件中可以劫持其他页面祸线程发起的网络请求,返回一个自定义的相应。
如果需要返回自定义请求,需要劫持原有请求,需要调用fetch 事件的 respondWith 方法。

respondWith 方法接收一个 Promise<Response> 对象作为参数,该Response对象将作为原请求的Response

Response对象,可以是在fetch 事件中调用fetch方法得到的Response,也可以是caches中缓存的Response,甚至是可以通过调用Response构造方法创建的Response对象。

其他说明

目前,服务线程只能采用cachesindexedDB两种存储方式。

Web应用清单 (Web App Manifest)

Web应用清单主要提供有关应用程序的信息(例如名称、图标和描述)。本质为JSON文件,其MIME建议为application/manifest+json

其主要有以下几个属性:

启动服务线程并加入清单文件

加入清单文件,只需要一个link标签即可,如:

<link rel="manifest" href="/manifest.json">

启动服务线程需要通过JavaScript实现:

if ('serviceWorker' in navigator) {           
  navigator.serviceWorker.register('/service-worker.js', {scope: '/'}).then(function (registration) {
    // 注册成功
    console.log('ServiceWorker registration successful with scope: ', registration.scope);
  }).catch(function (err) {                   
    // 注册失败 :(
    console.log('ServiceWorker registration failed: ', err);
  });
}
上一篇:Babel 配置入门教程
下一篇:Let's Encrypt 通配符证书申请教程